package com.gg.ai.controller;

import com.gg.ai.config.XingHuoGetWebsocketUrl;
import com.gg.ai.pojo.AnswerJson;
import com.gg.ai.pojo.JsonVariable;
import com.gg.ai.service.HandleHeader;
import com.gg.ai.service.HandleHistory;
import com.gg.ai.service.HandleParameter;
import com.google.gson.Gson;
import jakarta.websocket.*;
import jakarta.websocket.server.PathParam;
import jakarta.websocket.server.ServerEndpoint;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.WebSocketListener;
import okio.ByteString;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.net.MalformedURLException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.ConcurrentHashMap;

//@Slf4j
@Component
@ServerEndpoint("/websocket/{name}/{id}")
public class WebSocket {

    /**
     * 与某个客户端的连接对话，需要通过它来给客户端发送消息
     */
    private Session session;

    /**
     * 标识当前连接客户端的用户名
     */
    private String name;
    private int id;
    private String c = "";


    private static final Logger log = LoggerFactory.getLogger(WebSocket.class);

    /**
     * 用于存所有的连接服务的客户端，这个对象存储是安全的
     * 注意这里的kv,设计的很巧妙，v刚好是本类 WebSocket (用来存放每个客户端对应的MyWebSocket对象)
     */
    private static final ConcurrentHashMap<String, WebSocket> webSocketSet = new ConcurrentHashMap<>();

    String authUrl = XingHuoGetWebsocketUrl.getAuthUrl();
    OkHttpClient client = new OkHttpClient();

    public WebSocket() throws MalformedURLException, NoSuchAlgorithmException, InvalidKeyException {
    }

    /**
     * 连接建立成功调用的方法
     * session为与某个客户端的连接会话，需要通过它来给客户端发送数据
     */
    @OnOpen
    public void OnOpen(Session session, @PathParam(value = "name") String name, @PathParam(value = "id") int id) {
        log.info("----------------------------------");
        this.session = session;
        this.name = name;
        this.id = id;
        // name是用来表示唯一客户端，如果需要指定发送，需要指定发送通过name来区分
        webSocketSet.put(name + id, this);
        log.info("[WebSocket] 连接成功，当前连接人数为：={}", webSocketSet.size());
        log.info("----------------------------------");
        log.info("");
        AppointSending(name + id,name + id+"来了");
//        GroupSending(name + " 来了");
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void OnClose() {
        webSocketSet.remove(name+id);
        log.info("[WebSocket] 退出成功，当前连接人数为：={}", webSocketSet.size());
        System.out.println(JsonVariable.historyList);
//        ChatHistoryService chatHistoryService = ContextLoader.getCurrentWebApplicationContext().getBean(ChatHistoryService.class);
//        System.out.println(chatHistoryService.queryList(1,"1").getHistoryList());
//        GroupSending(name+id + " 走了");
        JsonVariable.historyList = null;
        // 关闭 OkHttpClient 对象
        client.dispatcher().executorService().shutdown();
    }

    /**
     * 收到客户端消息后调用的方法
     */
    @OnMessage
    public void OnMessage(String message_str) throws MalformedURLException, NoSuchAlgorithmException, InvalidKeyException {
        //  创建 Gson 对象
        Gson gson = new Gson();

        String url = authUrl.replace("http://", "ws://").replace("https://", "wss://");
        Request request = new Request.Builder()
                .url(url)
                .build();
        okhttp3.WebSocket ok_webSocket = client.newWebSocket(request, new WebSocketListener() {
            @Override
            public void onClosed(@NotNull okhttp3.WebSocket webSocket, int code, @NotNull String reason) {
                super.onClosed(webSocket, code, reason);
//                System.out.println(JsonVariable.historyList);
            }

            @Override
            public void onClosing(@NotNull okhttp3.WebSocket webSocket, int code, @NotNull String reason) {
                super.onClosing(webSocket, code, reason);
            }

            @Override
            public void onFailure(@NotNull okhttp3.WebSocket webSocket, @NotNull Throwable t, @Nullable Response response) {
                super.onFailure(webSocket, t, response);
            }

            @Override
            public void onMessage(@NotNull okhttp3.WebSocket webSocket, @NotNull String text) {
                // 在此处处理接收到的消息
                System.out.println("Received message: " + text);
                AnswerJson answerJson = gson.fromJson(text, AnswerJson.class);
                // token超过了
                if (answerJson.getHeader().getCode() == 10907) {
                    AppointSending(name + id, "本次会话历史已经超，请创建新的会话，不便之处请谅解");
                }
                if (answerJson.getHeader().getCode() != 0){
                    AppointSending(name + id, "后台出现错误，正在抢修请谅解");
                }
                String content = answerJson.getPayload().getChoices().getText().get(0).getContent();
                c+=content;
//      {"header":{"code":10907,"message":"TokenOverLimitError:(14:04:58.266) kernel error;code=1010","sid":"cht000bc32c@dx18dca4469f49a4b550","status":2}}

                if (answerJson.getHeader().getStatus() == 2) {
                    System.out.println(c);
                    JsonVariable.textArray.add(JsonVariable.createJsonObject("assistant",c));
                    c = "";
                    AppointSending(name + id, "{\"status\":2,\"content\":\""+ content + "\"}");
                }
                AppointSending(name + id, content);
            }

            @Override
            public void onMessage(@NotNull okhttp3.WebSocket webSocket, @NotNull ByteString bytes) {
                super.onMessage(webSocket, bytes);
            }

            @Override
            public void onOpen(@NotNull okhttp3.WebSocket webSocket, @NotNull Response response) {
                super.onOpen(webSocket, response);
            }
        });

        log.info("[WebSocket] 收到消息：{}", message_str);
        JsonVariable.question = message_str;
        HandleHeader h_t = new HandleHeader();
        HandleParameter p_t = new HandleParameter();
        HandleHistory history_t = new HandleHistory();
        Thread t1 = new Thread(h_t);
        Thread t2 = new Thread(p_t);
        Thread t3 = new Thread(history_t);
        t1.start();
        t2.start();
        t3.start();

        // 等待所有线程执行完成
        try {
            t1.join();
            t2.join();
            t3.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        JsonVariable.jsonObject.add("header", JsonVariable.headerObject);
        JsonVariable.jsonObject.add("parameter", JsonVariable.parameterObject);
        JsonVariable.jsonObject.add("payload", JsonVariable.payloadObject);

        String jsonString = gson.toJson(JsonVariable.jsonObject);
        System.out.println(jsonString);
        ok_webSocket.send(jsonString);


//        判断是否需要指定发送，具体规则自定义
//        System.out.println(message_str);
//        //message_str的格式 TOUSER:user2;message:aaaaaaaaaaaaaaaaaa;
//        if(message_str.indexOf("TOUSER") == 0){
//            //取出 name和message的值
//            String[] split = message_str.split(";");
//            String[] split1 = split[0].split(":");
//            String[] split2 = split[1].split(":");
//            String name = split1[1];
//            String message = split2[1];
//            //指定发送
//            AppointSending(name,message);
//        }else{
//            //群发
//            GroupSending(message_str);
//        }
    }

    /**
     * 发生错误时调用
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.info("发生错误");
        error.printStackTrace();
    }

    /**
     * 群发
     *
     * @param message
     */
    public void GroupSending(String message) {
        for (String name : webSocketSet.keySet()) {
            try {
                webSocketSet.get(name).session.getBasicRemote().sendText(message);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 指定发送
     *
     * @param name
     * @param message
     */
    public void AppointSending(String name, String message) {
        try {
            webSocketSet.get(name).session.getBasicRemote().sendText(message);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
